309. 最佳买卖股票时机含冷冻期

309. 最佳买卖股票时机含冷冻期

Similar Question

Solution Tips

方案一: 增加冷冻期状态

问题在于昨天的卖出还是被今天的买入参考了, 增加了一个冷冻期的判断没啥用

还是状态没搞清楚, 是不是可以分成昨天有卖出和没卖出, 两种状态?

var maxProfit = function(prices) {
    // 就是股票 II 加上了冷冻期, 还是用 dp 通用解的思路处理, 只不过能参考的变了一下
    // 1. dp[i][0/1] 代表第 i 天的时候, 不持有/持有股票, 所能获得的最大现金
    // 得加状态, 如果是持有股票了, 就一定不会处于冷冻期, 只有不持有股票的时候可能处于冷冻期
    // 将不持有股票拆分成2个状态, 不持有, 处于冷冻期 / 不持有, 不处于冷冻期
    // dp[i][0/1] 不持有, dp[i][2] 持有
    const n = prices.length;
    const dp = Array.from({length: prices.length}, () => Array.from({length: 3}))
    dp[0][0] = 0;
    dp[0][1] = 0;
    dp[0][2] = -prices[0];
    // 第 0 天的时候, 买入又卖出了, 导致今天处于冷冻期, 无法操作
    dp[1][1] = 0;

    for (let i = 1; i < prices.length; i++) {
        // 买入股票有冷冻期的限制, 这里需要改一下

        // 不持有股票 dp[i][0], 且不处于冷冻期
        // 可以是前一天已经持有了, 股票, 今天卖出
        // 前一天没有持有股票, 今天继续不持有
        dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2] + prices[i]);

        // 不持有股票, 且处于冷冻期
        // 前一天没有持有股票, 今天处于冷冻期, 说明是昨天卖出的
        if (i >= 2) {
            dp[i][1] = dp[i - 2][2] + prices[i - 1];
        }

        // 持有股票, 不可能处于冷冻期
        // 昨天没有持有股票, 且处于非冷冻期, 今天买入
        // 昨天没有持有股票, 且昨天处于冷冻期, 今天买入
        // 昨天持有股票, 今天继续持有
        dp[i][2] = Math.max(...[dp[i - 1][0] - prices[i] ,dp[i - 1][1] - prices[i], dp[i - 1][2]]);
    }

    return Math.max(dp[n - 1][0], dp[n - 1][1]);
};
console.log(maxProfit([1,2,3,0,2]));

方案二: 增加是否卖出的状态

虽然还是 3 个状态, 但是定义改变之后, 看问题的视角也跟着改变了, 成功解决问题

var maxProfit = function(prices) {
    // 就是股票 II 加上了冷冻期, 还是用 dp 通用解的思路处理, 只不过能参考的变了一下
    // 1. dp[i][0/1] 代表第 i 天的时候, 有卖出和没卖出, 所能获得的最大现金
    // 还是状态没搞清楚, 是不是可以分成有卖出和没卖出, 两种状态? 看看能不能建立起状态转移方程, 如果不行就全列了
    // 还是得加一个是否持有 , 3 中状态, 那和冷冻期又有什么区别呢?
    const n = prices.length;
    const dp = Array.from({length: prices.length}, () => Array.from({length: 3}))
    dp[0][0] = 0;
    dp[0][1] = 0;
    dp[0][2] = -prices[0];
    // 第 0 天的时候, 买入又卖出了, 导致今天处于冷冻期, 无法操作
    dp[1][0] = 0;

    for (let i = 1; i < prices.length; i++) {
        // 买入股票有冷冻期的限制, 这里需要改一下

        // 今天没有持有没有卖出 dp[i][0]
        // 昨天没有持有股票, 今天继续不持有, 那就一直都是 0, 没有意义, 是不是可以去掉
        // 昨天卖出了, 今天没有持有, 没有卖出
        if (i >= 2) {
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1]);
        }

        // 今天没有持有, 今天卖出了
        // 昨天持有了, 今天才能卖
        dp[i][1] = Math.max(dp[i - 1][2] + prices[i]);

        // 今天持有了, 今天没有卖出
        // 可能是昨天持有了, 今天继续持有
        // 昨天没有持有, 且昨天没有卖出, 今天买入
        dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][0] - prices[i]);
    }

    return Math.max(dp[n - 1][0], dp[n - 1][1]);
};
console.log(maxProfit([1,2,3,0,2]));

状态继续合并

var maxProfit = function(prices) {
    // 就是股票 II 加上了冷冻期, 还是用 dp 通用解的思路处理, 只不过能参考的变了一下
    // 1. dp[i][0/1] 代表第 i 天的时候, 有卖出和没卖出, 所能获得的最大现金
    // 还是状态没搞清楚, 是不是可以分成有卖出和没卖出, 两种状态? 看看能不能建立起状态转移方程, 如果不行就全列了
    // 还是得加一个是否持有 , 3 中状态, 那和冷冻期又有什么区别呢?
    const n = prices.length;
    const dp = Array.from({length: prices.length}, () => Array.from({length: 3}))
    dp[0][0] = 0;
    dp[0][1] = -prices[0];

    for (let i = 1; i < prices.length; i++) {
        // 买入股票有冷冻期的限制, 这里需要改一下

        // 今天没有持有没有卖出 dp[i][0]
        // 昨天没有持有股票, 今天继续不持有, 那就一直都是 0, 没有意义, 是不是可以去掉
        // 昨天卖出了, 今天没有持有, 没有卖出
        dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);

        if (i >= 2) {
            // 前天没有持有的状态, 就包括了当天卖出了, 这样昨天就是冷冻期, 不影响今天买入
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 2][0] - prices[i]);
        }
        else {
            dp[i][1] = Math.max(-prices[0], -prices[1]);
        }
    }

    return Math.max(dp[n - 1][0], dp[n - 1][1]);
};

确实是 ok 的, 有人表示就和打家劫舍是一样的